home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / UGPRG.ZIP / DENTHOR / TUT19.DOC < prev    next >
Encoding:
Text File  |  1996-07-27  |  29.1 KB  |  807 lines

  1.                    ╒═══════════════════════════════╕
  2.                    │         W E L C O M E         │
  3.                    │  To the VGA Trainer Program   │ │
  4.                    │              By               │ │
  5.                    │      DENTHOR of ASPHYXIA      │ │ │
  6.                    ╘═══════════════════════════════╛ │ │
  7.                      ────────────────────────────────┘ │
  8.                        ────────────────────────────────┘
  9.  
  10.                            --==[ PART 19 ]==--
  11.  
  12.  
  13.  
  14. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  15. ■ Introduction
  16.  
  17. Hi there. As promised in Tut 18, this trainer is on assembler. For those
  18. people who already know assembler quite well, this tut is also on the flame
  19. effect.
  20.  
  21. Okay, here is the total list of ways to get my trainers :
  22.  
  23. http://goth.vironix.co.za/~denthor                     (WWW)
  24. ftp.eng.ufl.edu pub/msdos/demos/code/graph/tutor       (FTP)
  25. denthor@beastie.cs.und.ac.za  Subject : request-list   (EMAIL)
  26.  
  27. As well as the BBS numbers shown at the end ... I will add a few ftp sits
  28. to that list (x2ftp.oulu.fi etc.)
  29.  
  30. Tut 20? How about 3d shading, hidden surface removal etc? Mail me :)
  31.  
  32.  
  33. If you would like to contact me, or the team, there are many ways you
  34. can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
  35.                   on the ASPHYXIA BBS.
  36.             2) Write to :  Grant Smith
  37.                            P.O.Box 270 Kloof
  38.                            3640
  39.                            Natal
  40.                            South Africa
  41.             3) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
  42.                   call during varsity). Call +27-31-73-2129 if you call
  43.                   from outside South Africa. (It's YOUR phone bill ;-))
  44.             4) Write to denthor@beastie.cs.und.ac.za in E-Mail.
  45.             5) Write to asphyxia@beastie.cs.und.ac.za to get to all of
  46.                us at once.
  47.  
  48. NB : If you are a representative of a company or BBS, and want ASPHYXIA
  49.        to do you a demo, leave mail to me; we can discuss it.
  50. NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
  51.         quite lonely and want to meet/help out/exchange code with other demo
  52.         groups. What do you have to lose? Leave a message here and we can work
  53.         out how to transfer it. We really want to hear from you!
  54.  
  55. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  56. ■  Assembler - the short version
  57.  
  58. Okay, there are many assembler trainers out there, many of which are
  59. probably better then this one. I will focus on the areas of assembler that
  60. I find important ... if you want more, go buy a book (go for the Michael
  61. Abrash ones), or scour the 'net for others.
  62.  
  63. First, let us start off with the basic set up of an assembler program.
  64.  
  65. DOSSEG
  66.  
  67. This tells your assembler program to order your segments in the same manner
  68. that high level languages do.
  69.  
  70. .MODEL <MODEL>
  71.  
  72. <MODEL> can be : Tiny       Code + Data < 64k   (Can be made a COM file)
  73.                  Small      Code < 64k          Data < 64k
  74.                  Medium     Code > 64k          Data < 64k
  75.                  Compact    Code < 64k          Data > 64k
  76.                  Large      Code > 64k          Data > 64k
  77.                  Huge       Arrays > 64k
  78.  
  79. .286
  80.  
  81. Enable 286 instructions ... can be .386 ; .386P etc.
  82.  
  83. .STACK <size>
  84.  
  85. <size> will be the size of your stack. I usually use 200h
  86.  
  87. .DATA
  88.  
  89. Tells the program that the data is about to follow. (Everything after this
  90. will be placed in the data segment)
  91.  
  92. .CODE
  93.  
  94. Tells the program that the code is about to follow. (Everything after this
  95. will be placed in the code segment)
  96.  
  97. START :
  98.  
  99. Tells the program that this is where the code begins.
  100.  
  101. END START
  102.  
  103. Tells the program that this is where the code ends.
  104.  
  105. To compile and run an assembler file, we run
  106. tasm bob
  107. tlink bob
  108.  
  109. I personally use tasm, you will have to find out how your assembler works.
  110.  
  111. Now, if we ran the above file as follows :
  112.  
  113. DOSSEG
  114. .MODEL SMALL
  115. .286
  116. .STACK 200h
  117. .DATA
  118. .CODE
  119.  
  120. START
  121. END START
  122.  
  123. You would think that is would just exit to dos immediately, right? Wrong.
  124. You have to specifically give dos back control, by doing the following :
  125.  
  126. START
  127.         mov     ax,4c00h
  128.         int     21h
  129. END START
  130.  
  131. Now if you compiled it, it would run and do nothing.
  132.  
  133. Okay, let us kick off with registers.
  134.  
  135. Firstly : A bit is a value that is either 1 or 0
  136.  
  137. This is obviously quite limited, but if we start counting in them, we can
  138. get larger numbers. Counting with ones and zeros is known as binary, and we
  139. call it base 2. Counting in normal decimal is known as base 10, and
  140. counting in hexidecimal is known as base 16.
  141.  
  142.     Base 2 (Binary)     Base 10 (Decimal)    Base 16 (Hexidecimal)
  143.          0                      0                       0
  144.          1                      1                       1
  145.          10                     2                       2
  146.          11                     3                       3
  147.          100                    4                       4
  148.          101                    5                       5
  149.          110                    6                       6
  150.          111                    7                       7
  151.          1000                   8                       8
  152.          1001                   9                       9
  153.          1010                   10                      A
  154.          1011                   11                      B
  155.          1100                   12                      C
  156.          1101                   13                      D
  157.          1110                   14                      E
  158.          1111                   15                      F
  159.  
  160. As you can see, you need four bits to count up to 15, and we call this a
  161. nibble. With eight bits, we can count up to 255, and we call this a byte.
  162. With sixteen bits, we can count up to 65535, and we call this a word. With
  163. thirty two bits, we can count up to lots, and we call this a double word. :)
  164.  
  165. A quick note : Converting from binary to hex is actually quite easy. You
  166. break up the binary into groups of four bits, starting on the right, and
  167. convers these groups of four to hex.
  168.  
  169.       1010 0010 1111 0001
  170.   =      A    2    F    1
  171.  
  172. Converting to decimal is a bit more difficult. What you do, is you multiply
  173. each number by it's base to the power of it's index ...
  174.  
  175.   A2F1 hex
  176. = (A*16^3) + (2*16^2) + (F*16^1) + (1*16^0)
  177. = (10*4096) + (2*256) + (15*16) + (1)
  178. = 40960 + 512 + 240 + 1
  179. = 41713 decimal
  180.  
  181. The same system can be used for binary.
  182.  
  183. To convert from decimal to another base, you divide the decimal value by the
  184. desired base, keeping a note of the remainders, and then reading the results
  185. backwards.
  186.  
  187.                16   |   41713
  188.                16   |   2607    r   1       (41713 / 16 = 2607 r 1)
  189.                16   |   162     r   F       (2607 / 16 = 162 r 15)
  190.                16   |   10      r   2       (162 / 16 = 10 r 2)
  191.                     |   0       r   A       (10 / 16 = 0 r 10)
  192.  
  193. Read the remainders bacckwards, our number is : A2F1 hex. Again, the same
  194. method can be used for binary.
  195.  
  196. The reason why hex is popular is obvious ... using bits, it is impossible
  197. to get a reasonable base 10 (decimal) system going, and binary get's unwieldly
  198. at high values. Don't worry too much though : most assemblers (like Tasm)
  199. will convert all your decimal values to hex for you.
  200.  
  201. You have four general purpose registers : AX, BX, CX and DX
  202. Think of them as variables that you will always have. On a 286, these
  203. registers are 16 bytes long, or one word.
  204.  
  205. As you know, a word consists of two bytes, and in assembler you can access
  206. these bytes individualy. They are separated into high bytes and low bytes per
  207. word.
  208.  
  209.    High Byte |  Low Byte
  210.    0000 0000 | 0000 0000  bits
  211.    [--------Word-------]
  212.  
  213. The method of access is easy. The high byte of AX is AH, and the low byte is
  214. AL ... you can also access BH, BL, CH, CL, DH and DL.
  215.  
  216. A 386 has extended registers : EAX, EBX, ECX, EDX ... you can access the
  217. lower word normally (as AX, with bytes AH and AL), but you cannot access the
  218. high word directly ... you must ror EAX,16 (rotate the binary value through
  219. 16 bits), after which the high word and low word swap ... do it again to
  220. return them. Acessing EAX as a whole is no problem ... mov eax,10 ;
  221. add eax,ebx ... these are all vaild.
  222.  
  223. Next come segments. As you have probably heard, computer memory is divided
  224. into various 64k segments (note : 64k = 65536 bytes, sound familiar?) A
  225. segment register points to which segment you are looking at. An offset
  226. register points to how far into that segment you are looking. One way
  227. of looking at it is like looking at a 2d array ... the segments are your
  228. columns and your offsets are your rows. Segments and offsets are displayed
  229. as Segment:Offset ... so $a000:50 would mean the fiftieth byte in segment
  230. $a000.
  231.  
  232. The segment registers are ES, DS, SS and CS. A 386 also has FS an GS.
  233. These values are words (0-65535), and you cannot access the high or low bytes
  234. separately. CS points to you your code segment, and usually if you touch this
  235. your program will explode. SS points to your stack segment, again, this
  236. baby is dangerous. DS points to your data segment, and can be altered, if
  237. you put it back after you use it, and don't use any global variables while
  238. it is altered. ES is your extra segment, and you can do what you want with
  239. it.
  240.  
  241. The offset registers are DI, SI, IP, SP, BP. Offset registers are generally
  242. asscociated with specific segment registers, as follows :
  243. ES:DI  DS:SI  CS:IP  SS:SP ... On a 286, BX can be used instead of the above
  244. offset registers, and on a 386, any register may be used. DS:BX is therefore
  245. valid.
  246.  
  247. If you create a global variable (let's say bob), when you access that
  248. variable, the compiler will actually look for it in the data segment.
  249. This means that the statement :
  250.  
  251. ax = bob
  252. could be
  253. ax = ds:[15]
  254.  
  255. A quick note : A value may be signed or unsigned. An unsigned word has a
  256. range from 0 to 65535. A signed word is called an integer and has a range
  257. -32768 to 32767. With a signed value, if the leftmost bit is equal to 1,
  258. the value is in the negative.
  259.  
  260. Next, let us have a look at the stack. Let us say that you want to save the
  261. value in ax, use ax to do other things, then restore it to it's origional
  262. value afterwards. This is done by utilising the stack. Have a look at the
  263. following code :
  264.  
  265. mov   ax, 50      ; ax is equal to 50
  266. push  ax          ; push ax onto the stack
  267. mov   ax, 27      ; ax is equal to 27
  268. pop   ax          ; pop ax off the stack
  269. At this point, ax is equal to 50.
  270.  
  271. Remember we defined the stack to be 200h further up? This is part of the
  272. reason we have it. When you push a value onto the stack, that value is
  273. recorded on the stack heap (referenced by SS:SP, SP is incremented) When you
  274. pop a value off the stack, the value is placed into the variable you are
  275. poping it back in to, SP is decremented and so forth. Note that the computer
  276. does not care what you pop the value back in to ...
  277.  
  278. mov   ax, 50
  279. push  ax
  280. pop   bx
  281.  
  282. Would set the values of both ax and bx to 50. (there are faster ways of doing
  283. this, pushing and poping are fairly fast though)
  284.  
  285. push ax
  286. push bx
  287. pop  ax
  288. pop  bx
  289.  
  290. would swap the values of ax and bx. As you can see, to pop the values back
  291. in to the origional variables, you must pop them back in the opposite
  292. direction to which you pushed them.
  293.  
  294. push ax
  295. push bx
  296. push cx
  297.  
  298. pop cx
  299. pop bx
  300. pop ax
  301.  
  302. would result in no change for any of the registers.
  303.  
  304. When a procedure is called, all the parameters for that procedure are pushed
  305. onto the stack. These can actually be read right off the stack, if you want
  306. to.
  307.  
  308. As you have already seen, the mov command moves a value...
  309.  
  310. mov  <dest>, <source>
  311.  
  312. Note that dest and source must be the same number of bits long...
  313.  
  314. mov  ax, dl
  315.  
  316. would not work, and neither would
  317.  
  318. mov  cl,bx
  319.  
  320. However, mov  cx,dx
  321.          mov  ax,50
  322.          mov  es,ax
  323. are all valid.
  324.  
  325. Shl I have explained before, it is where all the bits in a register are
  326. shifted one to the left and a zero added on to the right. This is the
  327. eqivalent of multiplying the value by two. Shr works in the opposite
  328. direction.
  329.  
  330. Rol does the same, except that the bit that is removed from the left is
  331. replaced on the right hand side. Ror works in the opposite direction.
  332.  
  333. div <value> divides the value in ax by value and returns the result in
  334. al if value is a byte, placing the remainder in ah. If value is a word,
  335. the double word DX:AX is divided by value, the result being placed in ax
  336. and the remainder in dx. Note that this only works for unsigned values.
  337.  
  338. idiv <value> does the same as above, but for signed variables.
  339.  
  340. mul <value>  If value is a byte, al is multiplied by value and the result
  341. is stored in ax. If value is a word, ax is multiplied by value and the
  342. result is stored in the double word DX:AX
  343.  
  344. imul <value> does the same as above, but for signed variables.
  345.  
  346. The j* commands are fairly simple : if a condition is met, jump to a certain
  347. lable.
  348.  
  349. jz  <label>   Jump if zero
  350. ja  <label>   Jump above     (unsigned)
  351. jg  <label>   Jump greater   (signed)
  352.  
  353. and so forth.
  354.  
  355. An example ...
  356.  
  357. cmp  ax,50    ; Compare ax to 50
  358. je   @Equal   ; If they are equal, jump to label @equal
  359.  
  360. call MyProc   Runs procedure MyProc and then returns to the next line of code.
  361.  
  362. Procedures are declared as follows :
  363.  
  364. MyProc   proc near
  365.            ret    ; Must be here to return from where it was called
  366. MyProc   endp
  367.  
  368. Variables are also easy :
  369.  
  370. bob  db 50
  371.  
  372. creates a variable bob, a byte, with an initial value of 50.
  373.  
  374. bob2 dw 50
  375.  
  376. creates a variable bob2, a word, with an initial value of 50.
  377.  
  378. bob3 db 1,2,3,4,5,65,23
  379.  
  380. creates bob3, an array of 7 bytes.
  381.  
  382. bob4 db 100 dup (?)
  383.  
  384. creates bob4, an array of 100 bytes, with no starting value.
  385.  
  386. Go back and look at tut 7 for a whole lot more assembler commands, and get
  387. some sort of reference guide to help you out with others. I personally use
  388. the Norton Guides help file to program assembler.
  389.  
  390.  
  391. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  392. ■  Fire Routines
  393.  
  394. To demonstrate how to write an assembler program, we will write a fire
  395. routine in 100% assembler. The theory is simple...
  396.  
  397. Set the pallette to go from white to yellow to red to blue to black.
  398. Create a 2d array representing the screen on the computer.
  399. Place high values at the bottom of the array (screen)
  400. for each element, do the following :
  401.   Take the average of the four elements under it
  402.  
  403.                          * Current element
  404.                         123
  405.                          4  Other elements
  406.   Get the average of the four elements, and place the result in the current
  407.   element.
  408. Repeat
  409.  
  410. Easy, no? I first saw a fire routine in the Iguana demo, and I just had to
  411. do one ;) ... it looks very effective.
  412.  
  413. With the sample file, I have created a batch file, make.bat ... it basically
  414. says :
  415.         tasm fire
  416.         tlink fire
  417.  
  418. So to build and run the fire program, type :
  419. make
  420. fire
  421.  
  422. The source file is commented quite well, so there shouldn't be any problems.
  423.  
  424.  
  425. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  426. ■  In closing
  427.  
  428. As you can see, the sample program is in 100% assembler. For the next tut
  429. I will return to Pascal, and hopefully your new found assembler skills will
  430. help you there too.
  431.  
  432.  
  433.  
  434. Byeeeee....
  435.   - Denthor
  436.  
  437. The following are official ASPHYXIA distribution sites :
  438.  
  439. ╔══════════════════════════╦════════════════╦═════╗
  440. ║BBS Name                  ║Telephone No.   ║Open ║
  441. ╠══════════════════════════╬════════════════╬═════╣
  442. ║ASPHYXIA BBS #1           ║+27-31-765-5312 ║ALL  ║
  443. ║ASPHYXIA BBS #2           ║+27-31-765-6293 ║ALL  ║
  444. ║C-Spam BBS                ║410-531-5886    ║ALL  ║
  445. ║POP!                      ║+27-12-661-1257 ║ALL  ║
  446. ║Soul Asylum               ║+358-0-5055041  ║ALL  ║
  447. ║Wasted Image              ║407-838-4525    ║ALL  ║
  448. ║Reckless Life             ║351-01-716 67 58║ALL  ║
  449. ║Mach 5 BBS                ║+1 319-355-7336 ║ALL  ║
  450. ║House of Horror           ║+1 513-734-6470 ║ALL  ║
  451. ║Zero Level                ║+39 6-810-9934  ║ALL  ║
  452. ╚══════════════════════════╩════════════════╩═════╝
  453.  
  454. Leave me mail if you want to become an official Asphyxia BBS
  455. distribution site.
  456. USES crt,dos;
  457.  
  458. VAR source,dest:string;
  459.  
  460.  
  461. function Exist(FileName: String): Boolean;
  462. { Boolean function that returns True if the file exists;otherwise,
  463.  it returns False. Closes the file if it exists. }
  464. var
  465.  F: file;
  466. begin
  467.  {$I-}
  468.  Assign(F, FileName);
  469.  FileMode := 0;  { Set file access to read only }
  470.  Reset(F);
  471.  Close(F);
  472.  {$I+}
  473.  Exist := (IOResult = 0) and (FileName <> '');
  474. end;
  475.  
  476. Procedure GetNames;
  477. BEGIN
  478.   writeln;
  479.   writeln ('Conversion from binary to db...');
  480.   writeln;
  481.   Write ('Enter name of binary file --> ');
  482.   Readln (source);
  483.   if not exist (source) then BEGIN
  484.     Writeln (source,' not found! Exiting ...');
  485.     writeln;
  486.     halt;
  487.   END;
  488.   Write ('Enter name of desination text file --> ');
  489.   Readln (dest);
  490.   writeln;
  491.   writeln ('Working ...');
  492. END;
  493.  
  494. Procedure Convert;
  495. VAR f:text;
  496.     f2:file;
  497.     loop1,loop2,loop3:integer;
  498.     no:byte;
  499.     msg:string;
  500.     dir:dirstr;
  501.     name:namestr;
  502.     ext:extstr;
  503. BEGIN
  504.   assign (f2,source);
  505.   reset (f2,1);
  506.   assign (f,dest);
  507.   rewrite (f);
  508.  
  509.   fsplit (dest, dir, name, ext);
  510.   while length (name)<8 do name:=name+' ';
  511.  
  512.   write (f,name,'  db ');
  513.   loop1:=0;
  514.   loop3:=filesize (f2);
  515.   loop2:=0;
  516.   While not EOF (f2) do BEGIN
  517.     blockread (f2,no,1);
  518.     str (no:3,msg);
  519.     write (f,msg);
  520.     inc (loop1);
  521.     inc (loop2);
  522.     gotoxy (1,wherey);
  523.     write (loop2,'/',loop3);
  524.     if (loop1=16) and (not (eof(f2))) then BEGIN
  525.       loop1:=0;
  526.       writeln(f);
  527.       write (f,'          db ');
  528.     END else
  529.     if not (eof(f2)) then write (f,',');
  530.   END;
  531.  
  532.   close (f);
  533.   close (f2);
  534.   writeln;
  535.  
  536.   writeln ('Done.');
  537. END;
  538.  
  539.  
  540. BEGIN
  541.   Getnames;
  542.   Convert;
  543. END.    DOSSEG          ; Order the program to order it's segments in the
  544.                     ; same way that high level languages do.
  545.  
  546.     .MODEL SMALL    ; Different models :
  547.                     ;     Tiny   : Code + Data < 64k  (can be made a COM file)
  548.                     ;     Small  : Code < 64k ;  Data < 64k
  549.                     ;     Medium : Code > 64k ;  Data < 64k
  550.                     ;     Compact: Code < 64k ;  Data > 64k
  551.                     ;     Large  : Code > 64k ;  Data > 64k
  552.                     ;     Huge   : Arrays > 64k
  553.  
  554.     .286            ; Enable 286 instructions
  555.  
  556.     .STACK 200h
  557.  
  558.     .DATA           ; Tells compiler that data is to follow.
  559.  
  560. endmessage db "This was the Fire Effect       - denthor@beastie.cs.und.ac.za$"
  561.                     ; This is our end message. Must be terminated with a "$"
  562. xsize    =  80      ; The x-width of our screen in pixels
  563. ysize    =  112      ; The y-height of our screen in pixels, plus a few extra
  564. randseed dw ?       ; any number for randomness
  565.  
  566. pallette db  0, 0, 0, 0, 0, 6, 0, 0, 6, 0, 0, 7, 0, 0, 8, 0, 0, 8, 0, 0, 9, 0, 0,10
  567.          db  2, 0,10, 4, 0, 9, 6, 0, 9, 8, 0, 8,10, 0, 7,12, 0, 7,14, 0, 6,16, 0, 5
  568.          db 18, 0, 5,20, 0, 4,22, 0, 4,24, 0, 3,26, 0, 2,28, 0, 2,30, 0, 1,32, 0, 0
  569.          db 32, 0, 0,33, 0, 0,34, 0, 0,35, 0, 0,36, 0, 0,36, 0, 0,37, 0, 0,38, 0, 0
  570.          db 39, 0, 0,40, 0, 0,40, 0, 0,41, 0, 0,42, 0, 0,43, 0, 0,44, 0, 0,45, 0, 0
  571.          db 46, 1, 0,47, 1, 0,48, 2, 0,49, 2, 0,50, 3, 0,51, 3, 0,52, 4, 0,53, 4, 0
  572.          db 54, 5, 0,55, 5, 0,56, 6, 0,57, 6, 0,58, 7, 0,59, 7, 0,60, 8, 0,61, 8, 0
  573.          db 63, 9, 0,63, 9, 0,63,10, 0,63,10, 0,63,11, 0,63,11, 0,63,12, 0,63,12, 0
  574.          db 63,13, 0,63,13, 0,63,14, 0,63,14, 0,63,15, 0,63,15, 0,63,16, 0,63,16, 0
  575.          db 63,17, 0,63,17, 0,63,18, 0,63,18, 0,63,19, 0,63,19, 0,63,20, 0,63,20, 0
  576.          db 63,21, 0,63,21, 0,63,22, 0,63,22, 0,63,23, 0,63,24, 0,63,24, 0,63,25, 0
  577.          db 63,25, 0,63,26, 0,63,26, 0,63,27, 0,63,27, 0,63,28, 0,63,28, 0,63,29, 0
  578.          db 63,29, 0,63,30, 0,63,30, 0,63,31, 0,63,31, 0,63,32, 0,63,32, 0,63,33, 0
  579.          db 63,33, 0,63,34, 0,63,34, 0,63,35, 0,63,35, 0,63,36, 0,63,36, 0,63,37, 0
  580.          db 63,38, 0,63,38, 0,63,39, 0,63,39, 0,63,40, 0,63,40, 0,63,41, 0,63,41, 0
  581.          db 63,42, 0,63,42, 0,63,43, 0,63,43, 0,63,44, 0,63,44, 0,63,45, 0,63,45, 0
  582.          db 63,46, 0,63,46, 0,63,47, 0,63,47, 0,63,48, 0,63,48, 0,63,49, 0,63,49, 0
  583.          db 63,50, 0,63,50, 0,63,51, 0,63,52, 0,63,52, 0,63,52, 0,63,52, 0,63,52, 0
  584.          db 63,53, 0,63,53, 0,63,53, 0,63,53, 0,63,54, 0,63,54, 0,63,54, 0,63,54, 0
  585.          db 63,54, 0,63,55, 0,63,55, 0,63,55, 0,63,55, 0,63,56, 0,63,56, 0,63,56, 0
  586.          db 63,56, 0,63,57, 0,63,57, 0,63,57, 0,63,57, 0,63,57, 0,63,58, 0,63,58, 0
  587.          db 63,58, 0,63,58, 0,63,59, 0,63,59, 0,63,59, 0,63,59, 0,63,60, 0,63,60, 0
  588.          db 63,60, 0,63,60, 0,63,60, 0,63,61, 0,63,61, 0,63,61, 0,63,61, 0,63,62, 0
  589.          db 63,62, 0,63,62, 0,63,62, 0,63,63, 0,63,63, 1,63,63, 2,63,63, 3,63,63, 4
  590.          db 63,63, 5,63,63, 6,63,63, 7,63,63, 8,63,63, 9,63,63,10,63,63,10,63,63,11
  591.          db 63,63,12,63,63,13,63,63,14,63,63,15,63,63,16,63,63,17,63,63,18,63,63,19
  592.          db 63,63,20,63,63,21,63,63,21,63,63,22,63,63,23,63,63,24,63,63,25,63,63,26
  593.          db 63,63,27,63,63,28,63,63,29,63,63,30,63,63,31,63,63,31,63,63,32,63,63,33
  594.          db 63,63,34,63,63,35,63,63,36,63,63,37,63,63,38,63,63,39,63,63,40,63,63,41
  595.          db 63,63,42,63,63,42,63,63,43,63,63,44,63,63,45,63,63,46,63,63,47,63,63,48
  596.          db 63,63,49,63,63,50,63,63,51,63,63,52,63,63,52,63,63,53,63,63,54,63,63,55
  597.          db 63,63,56,63,63,57,63,63,58,63,63,59,63,63,60,63,63,61,63,63,62,63,63,63
  598.            ; Our pallette ... generated elsewhere and brought in
  599.  
  600. screen   db xsize*ysize dup (?) ; Virtual screen
  601.  
  602.     .CODE           ; Tells compiler that code is to follow.
  603.  
  604.  
  605. Random          proc near
  606.  
  607.     mov     ax,[RandSeed]
  608.     mov     dx,8405h
  609.     mul     dx     ; ax*dx with result in dx:ax
  610.     inc     ax
  611.     mov     [RandSeed],ax
  612.     ret            ; Return back to main section
  613.  
  614. Random          endp
  615.  
  616.  
  617.  
  618. SetUpScreen     proc near
  619.  
  620.     mov     ax,0013h
  621.     int     10h       ; Get into 320x200x256 MCGA mode.
  622.  
  623.     mov     ax,0a000h
  624.     mov     es,ax
  625.     xor     di,di     ; ES:DI is now pointing to the top left hand of the screen
  626.  
  627.     cli
  628.     cld
  629.     mov     dx,3c4h
  630.     mov     ax,604h   ; Enter unchained mode
  631.     out     dx,ax
  632.     mov     ax,0F02h  ; All planes
  633.     out     dx,ax
  634.     xor     ax,ax
  635.     mov     cx,32767
  636.     rep     stosw     ; Clear the screen
  637.     mov     dx,3D4h
  638.     mov     ax,14h    ; Disable dword mode
  639.     out     dx,ax
  640.     mov     ax,0E317h ; Enable byte mode.
  641.     out     dx,ax
  642.     out     dx,ax
  643.     mov     ax,00409h ; Cell height
  644.     out     dx,ax
  645.  
  646.     mov     si, offset [pallette]
  647.     mov     dx, 3c8h  ; Pallette write register
  648.     mov     al, 0
  649.     out     dx, al    ; Start at color zero
  650.     inc     dx
  651.     mov     cx, 768
  652. @PalLoop :
  653.     outsb             ; Write value to port; inc DI
  654.     dec     cx
  655.     jnz     @PalLoop
  656.     ret
  657.  
  658. SetUpScreen    endp
  659.  
  660.  
  661.  
  662. START:
  663.     mov     ax,@DATA
  664.     mov     ds,ax     ; Moves the segment of the data into DS.
  665.  
  666.     call    SetUpScreen
  667.  
  668.     mov     randseed,1234h
  669.     mov     si,offset [screen]
  670.     mov     cx,xsize*ysize
  671.     xor     ax,ax
  672.     rep     stosb     ; Clear our virtual screen.
  673.  
  674. @MainLoop :
  675.  
  676.                       ;
  677.                       ; This next bit puts either 0 or 255 along the very
  678.                       ; bottom row of our virtual screen.
  679.                       ;
  680.  
  681.     mov     si,offset [screen]
  682.     add     si,xsize*ysize
  683.     sub     si,xsize  ; si=ofs(screen)+xsize*ysize-xsize ie. start of last row
  684.     mov     cx,xsize  ; loop the entire last row
  685.     xor     dx,dx
  686. @Newline :
  687.     call    random
  688.     mov     ds:[si],dl
  689.     inc     si
  690.     dec     cx
  691.     jnz     @Newline
  692.  
  693.                       ;
  694.                       ; This "softens" the values in the virtual array,
  695.                       ; creating a fire effect.
  696.                       ;
  697.     mov     cx,xsize*ysize
  698.     sub     cx,xsize
  699.     mov     si,offset [screen]
  700.     add     si,xsize
  701. @FileLoop :
  702.     xor     ax,ax
  703.     mov     al,ds:[si]
  704.     add     al,ds:[si+1]
  705.     adc     ah,0
  706.     add     al,ds:[si-1]
  707.     adc     ah,0
  708.     add     al,ds:[si+xsize]
  709.     adc     ah,0
  710.     shr     ax,2
  711.     jz      @zero
  712.     dec     ax
  713. @Zero :
  714.                       ; al = ((pos)+(pos+1)+(pos-1)+(pos+80))/4 - 1
  715.     mov     ds:[si-xsize],al
  716.     inc     si
  717.     dec     cx
  718.     jnz     @FileLoop
  719.  
  720.                       ;
  721.                       ; This dumps our virtual screen to the VGA screen.
  722.                       ;
  723.     mov     dx, 3dah
  724. l1:
  725.     in      al, dx
  726.     and     al, 8h
  727.     jnz     l1
  728. l2:
  729.     in      al, dx
  730.     and     al, 8h
  731.     jz      l2
  732.  
  733.     mov     cx,xsize*ysize
  734.     shr     cx,1
  735.     mov     si,offset [screen]
  736.     xor     di,di
  737.     rep     movsw
  738.  
  739.     mov     ah,01
  740.     int     16h       ; Has a key been pressed?
  741.     jz      @MainLoop ; If not, carry on.
  742.  
  743.     mov     ah,0
  744.     int     16h       ;get a key, returned in AX
  745.                       ;this is just to clear the keyboard buffer of the key
  746.                       ;press.
  747.  
  748.     mov     ax,0003h
  749.     int     10h       ; Get into 80x25 text mode
  750.  
  751.     mov     dx,offset [endmessage]
  752.     mov     ah,09h
  753.     int     21h       ; Dos interrupt 21, subfunction 09 ... print string.
  754.                       ; DS:DX must be pointing to start of string.
  755.  
  756.     mov     ax,4c00h  ; This function exits the program
  757.     int     21h       ; and returns control to DOS.
  758. END START
  759.  
  760. fire      db   0,  0,  0,  0,  0,  6,  0,  0,  6,  0,  0,  7,  0,  0,  8,  0
  761.           db   0,  8,  0,  0,  9,  0,  0, 10,  2,  0, 10,  4,  0,  9,  6,  0
  762.           db   9,  8,  0,  8, 10,  0,  7, 12,  0,  7, 14,  0,  6, 16,  0,  5
  763.           db  18,  0,  5, 20,  0,  4, 22,  0,  4, 24,  0,  3, 26,  0,  2, 28
  764.           db   0,  2, 30,  0,  1, 32,  0,  0, 32,  0,  0, 33,  0,  0, 34,  0
  765.           db   0, 35,  0,  0, 36,  0,  0, 36,  0,  0, 37,  0,  0, 38,  0,  0
  766.           db  39,  0,  0, 40,  0,  0, 40,  0,  0, 41,  0,  0, 42,  0,  0, 43
  767.           db   0,  0, 44,  0,  0, 45,  0,  0, 46,  1,  0, 47,  1,  0, 48,  2
  768.           db   0, 49,  2,  0, 50,  3,  0, 51,  3,  0, 52,  4,  0, 53,  4,  0
  769.           db  54,  5,  0, 55,  5,  0, 56,  6,  0, 57,  6,  0, 58,  7,  0, 59
  770.           db   7,  0, 60,  8,  0, 61,  8,  0, 63,  9,  0, 63,  9,  0, 63, 10
  771.           db   0, 63, 10,  0, 63, 11,  0, 63, 11,  0, 63, 12,  0, 63, 12,  0
  772.           db  63, 13,  0, 63, 13,  0, 63, 14,  0, 63, 14,  0, 63, 15,  0, 63
  773.           db  15,  0, 63, 16,  0, 63, 16,  0, 63, 17,  0, 63, 17,  0, 63, 18
  774.           db   0, 63, 18,  0, 63, 19,  0, 63, 19,  0, 63, 20,  0, 63, 20,  0
  775.           db  63, 21,  0, 63, 21,  0, 63, 22,  0, 63, 22,  0, 63, 23,  0, 63
  776.           db  24,  0, 63, 24,  0, 63, 25,  0, 63, 25,  0, 63, 26,  0, 63, 26
  777.           db   0, 63, 27,  0, 63, 27,  0, 63, 28,  0, 63, 28,  0, 63, 29,  0
  778.           db  63, 29,  0, 63, 30,  0, 63, 30,  0, 63, 31,  0, 63, 31,  0, 63
  779.           db  32,  0, 63, 32,  0, 63, 33,  0, 63, 33,  0, 63, 34,  0, 63, 34
  780.           db   0, 63, 35,  0, 63, 35,  0, 63, 36,  0, 63, 36,  0, 63, 37,  0
  781.           db  63, 38,  0, 63, 38,  0, 63, 39,  0, 63, 39,  0, 63, 40,  0, 63
  782.           db  40,  0, 63, 41,  0, 63, 41,  0, 63, 42,  0, 63, 42,  0, 63, 43
  783.           db   0, 63, 43,  0, 63, 44,  0, 63, 44,  0, 63, 45,  0, 63, 45,  0
  784.           db  63, 46,  0, 63, 46,  0, 63, 47,  0, 63, 47,  0, 63, 48,  0, 63
  785.           db  48,  0, 63, 49,  0, 63, 49,  0, 63, 50,  0, 63, 50,  0, 63, 51
  786.           db   0, 63, 52,  0, 63, 52,  0, 63, 52,  0, 63, 52,  0, 63, 52,  0
  787.           db  63, 53,  0, 63, 53,  0, 63, 53,  0, 63, 53,  0, 63, 54,  0, 63
  788.           db  54,  0, 63, 54,  0, 63, 54,  0, 63, 54,  0, 63, 55,  0, 63, 55
  789.           db   0, 63, 55,  0, 63, 55,  0, 63, 56,  0, 63, 56,  0, 63, 56,  0
  790.           db  63, 56,  0, 63, 57,  0, 63, 57,  0, 63, 57,  0, 63, 57,  0, 63
  791.           db  57,  0, 63, 58,  0, 63, 58,  0, 63, 58,  0, 63, 58,  0, 63, 59
  792.           db   0, 63, 59,  0, 63, 59,  0, 63, 59,  0, 63, 60,  0, 63, 60,  0
  793.           db  63, 60,  0, 63, 60,  0, 63, 60,  0, 63, 61,  0, 63, 61,  0, 63
  794.           db  61,  0, 63, 61,  0, 63, 62,  0, 63, 62,  0, 63, 62,  0, 63, 62
  795.           db   0, 63, 63,  0, 63, 63,  1, 63, 63,  2, 63, 63,  3, 63, 63,  4
  796.           db  63, 63,  5, 63, 63,  6, 63, 63,  7, 63, 63,  8, 63, 63,  9, 63
  797.           db  63, 10, 63, 63, 10, 63, 63, 11, 63, 63, 12, 63, 63, 13, 63, 63
  798.           db  14, 63, 63, 15, 63, 63, 16, 63, 63, 17, 63, 63, 18, 63, 63, 19
  799.           db  63, 63, 20, 63, 63, 21, 63, 63, 21, 63, 63, 22, 63, 63, 23, 63
  800.           db  63, 24, 63, 63, 25, 63, 63, 26, 63, 63, 27, 63, 63, 28, 63, 63
  801.           db  29, 63, 63, 30, 63, 63, 31, 63, 63, 31, 63, 63, 32, 63, 63, 33
  802.           db  63, 63, 34, 63, 63, 35, 63, 63, 36, 63, 63, 37, 63, 63, 38, 63
  803.           db  63, 39, 63, 63, 40, 63, 63, 41, 63, 63, 42, 63, 63, 42, 63, 63
  804.           db  43, 63, 63, 44, 63, 63, 45, 63, 63, 46, 63, 63, 47, 63, 63, 48
  805.           db  63, 63, 49, 63, 63, 50, 63, 63, 51, 63, 63, 52, 63, 63, 52, 63
  806.           db  63, 53, 63, 63, 54, 63, 63, 55, 63, 63, 56, 63, 63, 57, 63, 63
  807.           db  58, 63, 63, 59, 63, 63, 60, 63, 63, 61, 63, 63, 62, 63, 63, 63